package com.rongji.cms.tools.file.service.impl;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rongji.cms.tools.common.constant.CacheNames;
import com.rongji.cms.tools.common.core.domain.PageQuery;
import com.rongji.cms.tools.common.core.page.TableDataInfo;
import com.rongji.cms.tools.common.exception.ServiceException;
import com.rongji.cms.tools.common.utils.DateUtils;
import com.rongji.cms.tools.common.utils.StringUtils;
import com.rongji.cms.tools.common.utils.file.FileUtils;
import com.rongji.cms.tools.common.utils.redis.QueueUtils;
import com.rongji.cms.tools.file.constant.FileConstant;
import com.rongji.cms.tools.file.domain.ToolsOss;
import com.rongji.cms.tools.file.domain.vo.ToolsOssVo;
import com.rongji.cms.tools.file.enums.FileType;
import com.rongji.cms.tools.file.enums.FutureType;
import com.rongji.cms.tools.file.mapper.ToolsOssMapper;
import com.rongji.cms.tools.file.oss.core.OssClient;
import com.rongji.cms.tools.file.oss.entity.UploadResult;
import com.rongji.cms.tools.file.oss.factory.OssFactory;
import com.rongji.cms.tools.file.oss.properties.OssProperties;
import com.rongji.cms.tools.file.service.ToolsOssService;
import com.rongji.cms.tools.file.utils.PdfUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 文件处理
 *
 * @author yang
 * @create 2022/11/30
 **/
@Slf4j
@Service
public class ToolsOssServiceImpl implements ToolsOssService {

    @Resource
    private ToolsOssMapper toolsOssMapper;
    @Resource
    private OssProperties ossProperties;
    @Resource
    private PdfUtils pdfUtils;
    //config类里定义好的，这里得用Autowired注解，因为是spring管理的
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    //oss存储客户端
    OssClient storage;

    /**
     * 系统启动初始时候的一些操作，
     * 初始化oss客户端，订阅队列等
     */
    @Override
    public void init() {
//        oss客户端要在这里初始化
        storage = OssFactory.instance();
//     队列名用文件类型拼接，集中到enum里，循环订阅
        for (FileType fileType : FileType.values()) {
            String queueName = fileType + FileConstant.QUEUE_SUFFIX;
            log.info("通道: {}开始接收数据。。。。。。。。。。。。。。。。。。。", queueName);
            QueueUtils.subscribeBlockingQueue(queueName, (String ossId) -> {
                // 观察接收时间
                log.info("通道: {}, 收到数据: {}", queueName, ossId);
                handleFile(ossId);
            });
        }


    }


    /**
     * 上传文件
     * 远程调用的话，还是得传人员id
     *
     * @param file 文件
     * @param uid  人员id
     * @return
     */
    @Override
    public ToolsOss upload(MultipartFile file, String uid) {
//        文件原始名称
        String originalfileName = file.getOriginalFilename();
//        不带后缀名
        String mainName = originalfileName.substring(0, originalfileName.lastIndexOf("."));
//        文件大小
        long size = file.getSize();
//        后缀名,不带.
        String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf(".") + 1, originalfileName.length());
//      先上传到本地存储
        UploadResult uploadResult = localUpload(file, suffix);
        // 保存文件信息
        ToolsOss oss = new ToolsOss();
        oss.setFileUrl(uploadResult.getFileUrl());
        oss.setFileSuffix(suffix);
        oss.setFileSize(size);
        oss.setFilePath(uploadResult.getFilePath());
        oss.setFileName(uploadResult.getFilename());
        oss.setFileType(uploadResult.getFileType());
        oss.setOriginalName(mainName);
        oss.setService(ossProperties.getService());

//        记录上传人员id
        oss.setCreateBy(uid);
        oss.setUpdateBy(uid);
        toolsOssMapper.insert(oss);
        return oss;
    }

    /**
     * 先上传到本地存储
     *
     * @param file
     * @param suffix
     * @return
     */
    private UploadResult localUpload(MultipartFile file, String suffix) {
//        2022/11/16/0f58922c46d14856b29fbd64b379740a.txt
        // 生成uuid作为文件名
        String uuid = IdUtil.fastSimpleUUID();

        // 文件路径
        String path = datePathFolder() + File.separator + uuid + "." + suffix;
//        既是要建立的文件夹名,也是附件的类型
        String extFolder = getExtFolder(suffix);
//        文件路径
        //        C:/upload/document/2022/11/16/0f58922c46d14856b29fbd64b379740a.txt
        String filePath = ossProperties.getLocalHome() + File.separator + extFolder + File.separator + path;
//        文件url
        //       http://192.168.212.123:8093/document/2022/11/16/0f58922c46d14856b29fbd64b379740a.txt
//        本地存储这里还是不存域名了,只存相对地址,有需要的时候再拼接
        String fileUrl = "/" + extFolder + "/" + DateUtils.datePath() + "/" + uuid + "." + suffix;
        try {
            FileUtils.writeBytes(file.getBytes(), filePath);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
//
        return UploadResult.builder().fileUrl(fileUrl).filename(uuid).filePath(filePath).fileType(extFolder).build();
    }


    /**
     * 通过ossId获取数据
     *
     * @param ossId 存储id
     * @return
     */
    @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId")
    @Override
    public ToolsOss getById(Long ossId) {
        return toolsOssMapper.selectById(ossId);
    }


    /**
     * 通过ids删除数据
     *
     * @param ids
     * @param isValid
     * @return
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 做一些业务上的校验,判断是否需要校验
        }
        List<ToolsOss> list = toolsOssMapper.selectBatchIds(ids);
        for (ToolsOss toolsOss : list) {
//            如果是oss的，先删除oss上的
            if (!FileConstant.SERVICE_LOCAL.equals(toolsOss.getService())) {
                deleteOssFiles(toolsOss);
            }
            deleteLocalFiles(toolsOss);


        }
        return toolsOssMapper.deleteBatchIds(ids) > 0;
    }


    /**
     * 删除oss上的文件
     *
     * @param toolsOss
     */
    private void deleteOssFiles(ToolsOss toolsOss) {

        //                删除原始文档
        storage.delete(toolsOss.getFileUrl());
//        不同类型的文件要删除的也不一样
        String fileType = toolsOss.getFileType();
//        文档类型要删除的
        if (String.valueOf(FileType.DOCUMENT).equals(fileType)) {
//                删除pdf文档
            storage.delete(toolsOss.getPdfUrl());
//                删除图片文档
            List<String> imageNames = getImageNames(toolsOss.getImagePage(), toolsOss.getFileName());
            for (int i = 0; i < imageNames.size(); i++) {
                storage.delete(toolsOss.getImageFolderUrl() + imageNames.get(i));
            }
        }
//        图片类型要删除的
        else if (String.valueOf(FileType.IMAGE).equals(fileType)) {
            storage.delete(toolsOss.getImageThumbUrl());
        }
        //       视频类型要删除的
//        // FIXME: 2022/12/1 暂无
        else if (String.valueOf(FileType.VIDEO).equals(fileType)) {

        }
        //       其他类型要删除的
        /// FIXME: 2022/12/1 暂无
        else if (String.valueOf(FileType.OTHER).equals(fileType)) {

        }


    }

    /**
     * 删除本地存储的文件
     *
     * @param toolsOss
     */
    private void deleteLocalFiles(ToolsOss toolsOss) {
        //          再删除本地存储的文件
//        使用java8的Optional来判断相应字段是否为空，不为空的话执行删除操作
        Optional.ofNullable(toolsOss.getFilePath()).ifPresent(u -> {
            log.info("--------------删除原始文件:" + u);
            FileUtils.del(u);
        });
        Optional.ofNullable(toolsOss.getPdfPath()).ifPresent(u -> {
            log.info("--------------删除pdf文件:" + u);
            FileUtils.del(u);
        });
        Optional.ofNullable(toolsOss.getImageFolderPath()).ifPresent(u -> {
            log.info("--------------删除pdf转的图片:" + u);
            FileUtils.del(u);
        });
        Optional.ofNullable(toolsOss.getImageThumbPath()).ifPresent(u -> {
            log.info("--------------删除缩略图:" + u);
            FileUtils.del(u);
        });
    }


    @Override
    public TableDataInfo<ToolsOssVo> queryPageList(ToolsOss bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ToolsOss> lqw = buildQueryWrapper(bo);
        Page<ToolsOssVo> result = toolsOssMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }


    @Override
    public List<ToolsOssVo> listByIds(Collection<Long> ossIds) {
//        不明白为啥这样写，还是用最简单的方式吧
//        List<ToolsOssVo> list = new ArrayList<>();
//        for (Long id : ossIds) {
//            ToolsOssVo vo = SpringUtils.getAopProxy(this).getById(id);
//            if (ObjectUtil.isNotNull(vo)) {
//                list.add(vo);
//            }
//        }
        List<ToolsOssVo> list = toolsOssMapper.selectVoBatchIds(ossIds);
        return list;
    }


    private LambdaQueryWrapper<ToolsOss> buildQueryWrapper(ToolsOss bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ToolsOss> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getFileName()), ToolsOss::getFileName, bo.getFileName());
        lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), ToolsOss::getOriginalName, bo.getOriginalName());
        lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), ToolsOss::getFileSuffix, bo.getFileSuffix());
        lqw.eq(StringUtils.isNotBlank(bo.getFileUrl()), ToolsOss::getFileUrl, bo.getFileUrl());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
                ToolsOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.eq(StringUtils.isNotBlank(bo.getCreateBy()), ToolsOss::getCreateBy, bo.getCreateBy());
        lqw.eq(StringUtils.isNotBlank(bo.getService()), ToolsOss::getService, bo.getService());
        return lqw;
    }

    /**
     * 根据文件后缀得到存储的文件夹名称
     *
     * @param suffix
     * @return
     */
    private String getExtFolder(String suffix) {
        String extFolder = "";
        //        文档
        if (ossProperties.getDocExt().contains(suffix)) {
            extFolder = String.valueOf(FileType.DOCUMENT);
        }
//        图片
        else if (ossProperties.getImageExt().contains(suffix)) {
            extFolder = String.valueOf(FileType.IMAGE);
        }
//        视频
        else if (ossProperties.getVideoExt().contains(suffix)) {
            extFolder = String.valueOf(FileType.VIDEO);
        }
//        其他
        else if (ossProperties.getOtherExt().contains(suffix)) {
            extFolder = String.valueOf(FileType.OTHER);
        }
        return extFolder;
    }

    /**
     * 按日期生成文件夹,因为windows和linux分隔符不同,"/"使用File.separator
     * 2018/08/08
     *
     * @return
     */
    public String datePathFolder() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy") + File.separator + DateFormatUtils.format(now, "MM") + File.separator + DateFormatUtils.format(now, "dd");
    }


    /**
     * 把配置里所有可以上传的附件类型集中到一起，理论上只要不改配置就不会变化，
     * 因此加入到缓存,不需要过期
     * <p>
     * 这里id纯粹是为了设置key，无实际用途
     *
     * @return
     */
    @Override
    @Cacheable(cacheNames = CacheNames.ALL_ATTACHMENT_CACHENAME, key = "#id")
    public List<String> getAttachmentExtList(String id) {
        String attachmentStr = ossProperties.getDocExt() + "," + ossProperties.getImageExt() + "," + ossProperties.getOtherExt() + "," + ossProperties.getVideoExt();
        List<String> attachmentExtList = StringUtils.str2List(attachmentStr, ",", true, true);
        log.info("------------------------------全部附件类型被调用了");
        return attachmentExtList;
    }

    /**
     * 通过imagePage和imageName拼出图片的名称
     *
     * @param imagePage
     * @param imageName
     * @return
     */
    private List<String> getImageNames(long imagePage, String imageName) {
        List<String> imageNameList = new ArrayList<>();
        StringBuffer imgFilePath = null;
        for (int i = 0; i < imagePage; i++) {
            imgFilePath = new StringBuffer();
            imgFilePath.append(imageName)
                    .append("_")
                    .append(String.valueOf(i + 1))
                    .append(".png");
            imageNameList.add(imgFilePath.toString());
        }
        return imageNameList;
    }

    private void handleFile(String ossId) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        ToolsOss toolsOss = getById(Long.valueOf(ossId));

//        如果是图片文件类型并且需要转换
        boolean isImage = String.valueOf(FileType.IMAGE).equals(toolsOss.getFileType());
        if (ossProperties.isEnableImageConvert() && isImage) {
            imgConvert(toolsOss);
        }
//        如果是视频文件类型并且需要转换
        boolean isVideo = String.valueOf(FileType.VIDEO).equals(toolsOss.getFileType());
        if (ossProperties.isEnableVideoConvert() && isVideo) {

        }
//        如果是文档文件类型并且需要转换
        boolean isDoc = String.valueOf(FileType.DOCUMENT).equals(toolsOss.getFileType());
        if (ossProperties.isEnableDocConvert() && isDoc) {
            docConvert(toolsOss);
        }
//        如果需要上传到oss
        if (ossProperties.isEnable()) {
            upload2OssByThreads(toolsOss);
        }

        stopWatch.stop();
        log.info("{}类型处理完全部耗时:{}秒------------------------", toolsOss.getFileType(), stopWatch.getTotalTimeSeconds());

    }


    private void imgConvert(ToolsOss toolsOss) {
        log.info("缩略图转换开始------------------------");
//        本地的转换
//        1,整理需要的各项参数
//        -------------------------------------------------------------------------------------
        String srcPath = toolsOss.getFilePath();
        String desPath = ossProperties.getLocalHome();
        log.info("源文件：" + srcPath);
        log.info("目标文件夹：" + desPath);
//            拼接转换后的文件名
        String mainName = FileNameUtil.mainName(srcPath);
        String suffix = FileNameUtil.extName(srcPath);
        String fileName = mainName + FileConstant.THUMB_SCALE;
        log.info("缩略图文件名：" + fileName);
        String thumbnailPath = desPath + File.separator + String.valueOf(FileType.IMAGE) + File.separator + datePathFolder() + File.separator + fileName + "." + suffix;
        log.info("缩略图文件路径:" + thumbnailPath);
        String thumbnailUrl = "/" + String.valueOf(FileType.IMAGE) + "/" + DateUtils.datePath() + "/" + fileName + "." + suffix;
        log.info("缩略图预览路径:" + thumbnailUrl);
//        暂时不补颜色，按原来cms的缩放为140x140的
        ImgUtil.scale(FileUtils.file(srcPath), FileUtils.file(thumbnailPath), FileConstant.THUMB_WIDTH, FileConstant.THUMB_HEIGHT, null);
//         FIXME: 2022/11/30  还是按一般情况就给个缩放比例？
//        ImgUtil.scale(FileUtils.file(srcPath), FileUtils.file(thumbnailPath), 0.4F);
        toolsOss.setImageThumbPath(thumbnailPath);
        toolsOss.setImageThumbUrl(thumbnailUrl);
        //        都转换成功后保存缩略图
        toolsOssMapper.updateById(toolsOss);
        log.info("缩略图转换完成------------------------");
    }


    /**
     * @param toolsOss
     */
    @Override
    public void docConvert(ToolsOss toolsOss) {
        log.info("文档转换开始------------------------");
//        本地的转换

//        1,整理需要的各项参数
//        -------------------------------------------------------------------------------------
        String srcPath = toolsOss.getFilePath();
        String desPath = ossProperties.getLocalHome();
        log.info("源文件：" + srcPath);
        log.info("目标文件夹：" + desPath);
//            拼接转换后的文件名
        String fileName = FileNameUtil.mainName(srcPath);
        String suffix = FileNameUtil.extName(srcPath);
        log.info("转换后文件名：" + fileName);
        String pdfFilePath = desPath + File.separator + String.valueOf(FileType.DOCUMENT) + File.separator + datePathFolder() + File.separator + fileName + "." + FileConstant.PDF_SUFFIX;
        log.info("pdf文件路径:" + pdfFilePath);
//        2,pdf转换
//        -------------------------------------------------------------------------------------
//      pdf文件特殊处理，不做转pdf操作
        if (!FileConstant.PDF_SUFFIX.equals(suffix)) {
            pdfUtils.toPdfSync(srcPath, pdfFilePath);
        }

        String pdfUrl = "/" + String.valueOf(FileType.DOCUMENT) + "/" + DateUtils.datePath() + "/" + fileName + FileConstant.PDF_SUFFIX;
        toolsOss.setPdfPath(pdfFilePath);
        toolsOss.setPdfUrl(pdfUrl);

//        3,pdf文件转为图片
//        -------------------------------------------------------------------------------------
        String imagePDFName = FileNameUtil.mainName(pdfFilePath);
        String imageFolderPath = desPath + File.separator + String.valueOf(FileType.IMAGE) + File.separator + datePathFolder() + File.separator + imagePDFName + File.separator;
        String imageFolderUrl = "/" + String.valueOf(FileType.IMAGE) + "/" + DateUtils.datePath() + "/" + imagePDFName + "/";
        long imagePage = pdfUtils.pdf2Image(pdfFilePath, imageFolderPath, imagePDFName, ossProperties.getDpi());
        toolsOss.setImageFolderPath(imageFolderPath);
        toolsOss.setImageFolderUrl(imageFolderUrl);
        toolsOss.setImagePage(imagePage);
//        都转换成功后保存pdf和image相关信息
        toolsOssMapper.updateById(toolsOss);
        log.info("文档转换完成------------------------");
    }


    /**
     * 本地存储的文件上传到oss,多线程方式
     * 因为原始文件、转换后的pdf文档、图片等是可以并行处理的，可以采用多线程方式
     * 各种本地文件上传完成再后执行数据库update
     * 使用CompletableFuture实现
     */
    @Override
    public void upload2OssByThreads(ToolsOss toolsOss) {
        log.info("上传到oss开始------------------------");

//        将执行的上传线程加入到list，每个uploadAsync根据条件判断是否上传
        LinkedList<CompletableFuture> futureList = new LinkedList<>();
        for (FutureType futureType : FutureType.values()) {
            CompletableFuture future = uploadAsync(toolsOss, futureType);
            futureList.add(future);
        }

//      fixme 转CompletableFuture[]数组时候要这样写，强制类型转换会有问题的
        CompletableFuture[] futures = futureList.toArray(new CompletableFuture[futureList.size()]);
//        全部上传后，更新数据库
        completeAsync(toolsOss, futures);

    }

    @NotNull
    private CompletableFuture uploadAsync(ToolsOss toolsOss, FutureType futureType) {
        CompletableFuture future = CompletableFuture
                // 根据条件判断上传的操作，以后有新的就在这里加case
                .supplyAsync(
                        () -> {
                            String taskName = "";
                            switch (futureType) {
                                case futureFile:
                                    taskName = uploadFileTask(toolsOss);
                                    break;
                                case futureThumb:
                                    taskName = uploadThumbTask(toolsOss);
                                    break;
                                case futureVideoThumb:
                                    taskName = uploadVideoThumbTask(toolsOss);
                                    break;
                                case futurePdf:
                                    taskName = uploadPdfTask(toolsOss);
                                    break;
                                case futureImg:
                                    taskName = uploadImgTask(toolsOss);
                                    break;
                                default:
                                    break;
                            }

                            return taskName;
                        }, threadPoolTaskExecutor);
        return future;
    }


    /**
     * 获取当前线程名称
     *
     * @return
     */
    private String getThreadName() {
        Thread currentThread = Thread.currentThread();
        String threadName = currentThread.getName();
        return threadName;
    }

    private String uploadFileTask(ToolsOss toolsOss) {
        String taskName = "原始文件上传到oss";
        log.info(getThreadName() + " 开始执行任务：" + taskName);
        storage.upload(toolsOss.getFilePath(), toolsOss.getFileUrl());
        log.info("----------------------------newFileUrl:" + storage.getUrl() + toolsOss.getFileUrl());
        toolsOss.setFileUrl(storage.getUrl() + toolsOss.getFileUrl());
        log.info(taskName + "执行结束");
        return taskName;
    }

    private String uploadThumbTask(ToolsOss toolsOss) {
        String taskName = "上传转换后的缩略图文件";
        log.info(getThreadName() + " 开始执行任务：" + taskName);
        String imageThumbPath = toolsOss.getImageThumbPath();
        if (StringUtils.isNotEmpty(imageThumbPath)) {
            storage.upload(imageThumbPath, toolsOss.getImageThumbUrl());
            log.info("----------------------------imageThumbUrl:" + storage.getUrl() + toolsOss.getImageThumbUrl());
            toolsOss.setImageThumbUrl(storage.getUrl() + toolsOss.getImageThumbUrl());
            log.info(taskName + "执行结束");
        } else {
            taskName = taskName + "无需执行";
            log.info(taskName);
        }
        return taskName;
    }

    /**
     * 暂时没用
     *
     * @param toolsOss
     * @return
     */
    private String uploadVideoThumbTask(ToolsOss toolsOss) {
        String taskName = "上传转换后的缩略视频文件";
        log.info(getThreadName() + " 开始执行任务：" + taskName);
        String videoThumbPath = toolsOss.getImageThumbPath();
        if (StringUtils.isNotEmpty(videoThumbPath)) {

            log.info(taskName + "执行结束");
        } else {
            taskName = taskName + "无需执行";
            log.info(taskName);
        }
        return taskName;
    }

    private String uploadPdfTask(ToolsOss toolsOss) {
        String taskName = "上传转换后的pdf文件";
        log.info(getThreadName() + " 开始执行任务：" + taskName);
        String pdfFilePath = toolsOss.getPdfPath();
        if (StringUtils.isNotEmpty(pdfFilePath)) {
            storage.upload(pdfFilePath, toolsOss.getPdfUrl());
            log.info("----------------------------newPdfUrl:" + storage.getUrl() + toolsOss.getPdfUrl());
            toolsOss.setPdfUrl(storage.getUrl() + toolsOss.getPdfUrl());
            log.info(taskName + "执行结束");
        } else {
            taskName = taskName + "无需执行";
            log.info(taskName);
        }
        return taskName;
    }

    private String uploadImgTask(ToolsOss toolsOss) {
        String taskName = "上传转换后的图片文件";
        log.info(getThreadName() + " 开始执行任务：" + taskName);
        long imagePage = toolsOss.getImagePage();
        //      image文件,可能有多个,循环上传,更新imageFolderUrl,其他地方要是调用,还是再继续拼接url
        if (imagePage != 0) {
            List<String> imageNames = getImageNames(imagePage, toolsOss.getFileName());
            for (int i = 0; i < imageNames.size(); i++) {
                storage.upload(toolsOss.getImageFolderPath() + imageNames.get(i), toolsOss.getImageFolderUrl() + imageNames.get(i));
                log.info("----------------------------newimageUrl:" + storage.getUrl() + toolsOss.getImageFolderUrl() + imageNames.get(i));
            }
            toolsOss.setImageFolderUrl(storage.getUrl() + toolsOss.getImageFolderUrl());
            log.info(taskName + "执行结束");
        } else {
            taskName = taskName + "无需执行";
            log.info(taskName);
        }
        return taskName;

    }


    /**
     * 等各个线程上传任务结束后，更新数据库
     *
     * @param toolsOss
     * @param futures
     */
    private void completeAsync(ToolsOss toolsOss, CompletableFuture[] futures) {
        CompletableFuture.allOf(futures)
                // 全部完成后，更新数据库
                .whenCompleteAsync(
                        (v, e) -> {
                            List<Object> values = new ArrayList<>();
                            for (CompletableFuture future : futures) {
                                try {
                                    values.add(future.get());
                                } catch (Exception ex) {
//                                    这里异常处理怎么做？
                                }
                            }
                            String threadName = getThreadName();
                            String taskName = "更新数据库数据";
                            log.info(threadName + " 开始执行任务：" + taskName);
                            log.info("前面任务的处理结果：" + values);
                            //        上传到oss后,更新这些的url为oss的地址
                            toolsOssMapper.updateById(toolsOss);

                            log.info(taskName + " 执行结束");
                            log.info("上传到oss完成------------------------");
                        }, threadPoolTaskExecutor);
    }


}




